package com.yjw.demo.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @author: James Yin
 * @description: 服务端
 * @date: 3/18/2020 6:40 PM
 */
public class Server {
    // 默认端口号
    private static final int DEFAULT_SERVER_PORT = 8888;
    private static final ByteBuffer BYTE_BUFFER = ByteBuffer.allocate(1024);
    private static Selector selector;

    /**
     * 启动服务
     *
     * @param args
     */
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 绑定地址
        serverSocketChannel.bind(new InetSocketAddress(DEFAULT_SERVER_PORT));
        // 设置非阻塞模式，NIO模型默认是采用阻塞式
        serverSocketChannel.configureBlocking(false);
        // 创建一个多路复用器
        selector = Selector.open();
        // 把serverSocketChannel注册到Selector上，监听ACCEPT事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 轮询主线程
        while (true) {
            //
            selector.select();
            // 获取所有事件
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = keys.iterator();
            // 这里是同步处理，每次只能处理一种事件
            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                // 移除已经取出的事件
                keyIterator.remove();
                // 处理事件
                process(key);
            }
        }
    }

    /**
     * 处理事件
     *
     * @param key
     */
    private static void process(SelectionKey key) throws IOException {
        // 处理接收事件
        if (key.isAcceptable()) {
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
            SocketChannel socketChannel = serverSocketChannel.accept();
            // 设置非阻塞模式
            socketChannel.configureBlocking(false);
            // 注册读事件
            socketChannel.register(selector, SelectionKey.OP_READ);
        }
        // 处理读事件
        else if (key.isReadable()) {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            int len = socketChannel.read(BYTE_BUFFER);
            if (len > 0) {
                BYTE_BUFFER.flip();
                String content = new String(BYTE_BUFFER.array(), 0, len);
                System.out.println("服务端收到消息：" + content);
                // 注册写事件
                key = socketChannel.register(selector, SelectionKey.OP_WRITE);
                // 在key上添加一个附件，后面写事件会把内容写出去
                key.attach(content);
            }
        }
        // 处理写事件
        else if (key.isWritable()) {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            String content = (String) key.attachment();
            socketChannel.write(ByteBuffer.wrap(("输出：" + content).getBytes()));
            socketChannel.close();
        }
    }
}
